import 'dart:async';

import "package:flutter/material.dart";
import 'package:flutter/scheduler.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:sample2/helper/app_helper.dart';
import 'package:sample2/helper/chat_helper.dart';
import 'package:sample2/model/chat/chat_group.dart';
import 'package:sample2/model/chat/chat_group_message.dart';
import 'package:sample2/model/chat/chat_user.dart';
import 'package:sample2/model/chat/message.dart';
import 'package:sample2/model/user_info.dart';
import 'package:sample2/services/chat_service.dart';
import 'package:sample2/helper/app_helper.dart';
import 'package:uuid/uuid.dart';

enum Menu {
  itemOne,
  itemTwo,
  itemThree,
  itemFour,
}

class ChatConversation extends StatefulWidget {
  const ChatConversation({super.key});
  @override
  State<StatefulWidget> createState() {
    return ChatConversationState();
  }
}

enum ChatConversationKind { peer2peer, peer2group }

//TODO: 消息紀錄
class ChatConversationState extends State<ChatConversation> {
  List<ChatMessage> messages = [];
  ChatUser? _toUser;
  ChatGroup? _toGroup;
  late ChatConversationKind _conversationType = ChatConversationKind.peer2peer;
  late final ScrollController _scrollController;
  late final TextEditingController _textEditingController;
  late final FocusNode _textFieldFocusNode;
  bool _shouldShowToolsPanel = false;
  String? _inputText;
  int? newMsgHandler;

  @override
  void initState() {
    _scrollController = ScrollController();
    _textEditingController = TextEditingController.fromValue(null);
    _textFieldFocusNode = FocusNode();
    _textFieldFocusNode.addListener(() {
      if (_textFieldFocusNode.hasPrimaryFocus) {
        if (_shouldShowToolsPanel && mounted) {
          setState(() {
            _shouldShowToolsPanel = false;
          });
        }
        //在獲取焦點完後等0.5秒將視圖自動上滾，避免被鍵盤擋住
        Timer(const Duration(milliseconds: 500), () {
          _scrollToBottom(0);
        });
      }
    });
    newMsgHandler = ChatHelper.addNewMessageListener((ChatMessage comingMsg) {
      //
      if ((_conversationType == ChatConversationKind.peer2peer &&
              comingMsg.from == _toUser?.chatId) ||
          (_conversationType == ChatConversationKind.peer2group &&
              (comingMsg as ChatGroupMessage).groupId == _toGroup?.groupId)) {
        if (!messages
            .any((tmpMsg) => tmpMsg.messageId == comingMsg.messageId)) {
          List<ChatMessage> newMessages = List.castFrom(messages);
          newMessages.add(comingMsg);
          if(mounted){
            setState(() {
              messages = newMessages;
            });
          }
          //TODO:remove the animation the first time loaded the messages
          _scrollToBottom(500);
        }
      }
    });
    super.initState();
  }

  void _scrollToBottom(int duration) {
    SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
      _scrollController.animateTo(_scrollController.position.maxScrollExtent,
          duration: Duration(milliseconds: duration),
          curve: Curves.fastOutSlowIn);
    });
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    Map arguments = (ModalRoute.of(context)!.settings.arguments ?? {}) as Map;
    ChatConversationKind conversationKind =
        arguments["kind"] ?? ChatConversationKind.peer2peer;
    if (conversationKind == ChatConversationKind.peer2group) {
      ChatGroup group = arguments["group"];
      EasyLoading.show();
      ChatHelper.joinGroup(group.groupId, () {
        setState(() {
          _conversationType = conversationKind;
          _toGroup = group;
        });
        Timer(const Duration(milliseconds: 500), () {
          getGroupHistory(group.groupId).then((List<ChatMessage>? msgs) {
            EasyLoading.dismiss();
            setState(() {
              messages = msgs ?? [];
            });
            //TODO:remove the animation the first time loaded the messages
            _scrollToBottom(500);
          });
        });
        debugPrint("join group ${group.groupId} success");
      }, (int code, String message) {
        debugPrint("join group ${group.groupId} failed");
      });
    } else {
      getPrivateHistory();
      setState(() {
        _conversationType = conversationKind;
        _toUser = arguments["toUser"];
      });
    }
  }

  @override
  void dispose() {
    ChatHelper.removeNewMessageListener(newMsgHandler);
    ChatHelper.releaseToUser();
    super.dispose();
  }

  Future<List<ChatMessage>?> getGroupHistory(String groupId) {
    return ChatService.getGroupMessages(groupId: groupId);
  }

  void getPrivateHistory() {
    EasyLoading.show();
    ChatHelper.getCurrentUser().then((ChatUser? user) {
      ChatService.getMessage(
              from: user?.userId ?? "", to: _toUser?.userId ?? "")
          .then((List<ChatMessage>? msgs) {
        EasyLoading.dismiss();
        setState(() {
          messages = msgs ?? [];
        });
        _scrollToBottom(500);
        Timer(const Duration(milliseconds: 500), () {
          _scrollToBottom(500);
        });
      }).catchError((error) {
        EasyLoading.dismiss();
        debugPrint(error.toString());
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Theme(
        data: Theme.of(context),
        child: Scaffold(
          appBar: _buildAppBar(),
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [_buildMessageList(), _buildBottomBar()],
          ),
        ));
  }

  _buildAppBar() {
    return AppBar(
      elevation: 0,
      automaticallyImplyLeading: false,
      backgroundColor: Colors.white,
      flexibleSpace: SafeArea(
        child: Container(
          padding: const EdgeInsets.only(right: 16),
          child: Row(children: <Widget>[
            IconButton(
              onPressed: () {
                Navigator.pop(context);
              },
              icon: const Icon(
                Icons.arrow_back,
                color: Colors.black,
              ),
            ),
            const SizedBox(
              width: 2,
            ),
            CircleAvatar(
              backgroundImage: NetworkImage(
                  "${AppHelper.shared.getBkDomainName()}/images/2022-12-07T01:54:19.821Z_labi.jpg"),
              maxRadius: 20,
            ),
            const SizedBox(
              width: 12,
            ),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    _toUser?.userName ?? _toGroup?.groupName ?? "--",
                    style: TextStyle(color: Colors.grey.shade600, fontSize: 13),
                  )
                ],
              ),
            ),
            Theme(
              data: Theme.of(context).copyWith(
                cardColor: Colors.amber,
              ),
              child: PopupMenuButton<Menu>(
                position: PopupMenuPosition.over,
                child: const Icon(Icons.settings),
                itemBuilder: (context) {
                  return <PopupMenuEntry<Menu>>[
                    const PopupMenuItem<Menu>(
                      value: Menu.itemOne,
                      child: Text("Item 1"),
                    ),
                    const PopupMenuItem<Menu>(
                      value: Menu.itemTwo,
                      child: Text("Item 2"),
                    ),
                    const PopupMenuItem<Menu>(
                      value: Menu.itemThree,
                      child: Text("Item 3"),
                    ),
                    const PopupMenuItem<Menu>(
                      value: Menu.itemFour,
                      child: Text("Item 4"),
                    )
                  ];
                },
              ),
            )
          ]),
        ),
      ),
    );
  }

  _buildMessageList() {
    return Expanded(
      child: RefreshIndicator(
        onRefresh: () async {},
        child: ListView.builder(
          physics: const AlwaysScrollableScrollPhysics(),
          keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
          controller: _scrollController,
          itemCount: messages.length,
          shrinkWrap: true,
          padding: const EdgeInsets.only(top: 10, bottom: 10),
          clipBehavior: Clip.none,
          itemBuilder: (context, index) {
            ChatMessage message = messages[index];
            return Container(
              padding: const EdgeInsets.only(
                  left: 14, right: 14, top: 10, bottom: 10),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: message.messageSenderReceiverType ==
                        ChatMessageSenderReceiverType.receiver
                    ? MainAxisAlignment.start
                    : MainAxisAlignment.end,
                textDirection: message.messageSenderReceiverType ==
                        ChatMessageSenderReceiverType.receiver
                    ? TextDirection.ltr
                    : TextDirection.rtl,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Container(
                        constraints: const BoxConstraints(maxWidth: 50),
                        child: Text(
                          message.fromNickName ?? "",
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                      CircleAvatar(
                        radius: 25,
                        foregroundImage: NetworkImage(message.getAvatarUrl()),
                      ),
                    ],
                  ),
                  const SizedBox(
                    width: 8,
                    height: 1,
                  ),
                  Container(
                    constraints: BoxConstraints(
                        //add constraint thus the selectableText could update height and auto mutilline
                        maxWidth:
                            (MediaQuery.of(context).size.width - 58) * 0.8),
                    margin: const EdgeInsets.fromLTRB(0, 20, 0, 0),
                    padding: const EdgeInsets.all(16),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(20),
                        color: (message.messageSenderReceiverType ==
                                ChatMessageSenderReceiverType.receiver
                            ? Colors.grey.shade200
                            : Colors.blue[200])),
                    child: SelectableText(
                      messages[index].message,
                      toolbarOptions:
                          const ToolbarOptions(selectAll: true, copy: true),
                      style: const TextStyle(
                        fontSize: 15,
                      ),
                    ),
                  ),
                  const Spacer(),
                ],
              ),
            );
          },
        ),
      ),
    );
  }

  _buildBottomBar() {
    return Column(children: [
      Container(
        padding: const EdgeInsets.all(10),
        constraints: const BoxConstraints(maxHeight: 260, minHeight: 60),
        decoration: const BoxDecoration(
            color: Color(0xffffffff),
            border: Border(
                top: BorderSide(
                  color: Colors.grey,
                  width: 1,
                  style: BorderStyle.solid,
                ),
                bottom: BorderSide.none,
                left: BorderSide.none,
                right: BorderSide.none)),
        child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: <
            Widget>[
          GestureDetector(
              onTap: () {
                if (_textFieldFocusNode.hasPrimaryFocus) {
                  _textFieldFocusNode.unfocus();
                }
                setState(() {
                  _shouldShowToolsPanel = true;
                });
              },
              child: Container(
                margin: const EdgeInsets.only(top: 5),
                height: 30,
                width: 30,
                decoration: BoxDecoration(
                    color: Colors.lightBlue,
                    borderRadius: BorderRadius.circular(30)),
                child: const Icon(
                  Icons.add,
                  color: Colors.white,
                  size: 20,
                ),
              )),
          const SizedBox(width: 15),
          Expanded(
            child: TextField(
              maxLines: 4, //當設置maxlines時需設置minlines，不然會自動展開最大高度
              minLines: 1,
              controller: _textEditingController,
              focusNode: _textFieldFocusNode,
              decoration: const InputDecoration(
                  contentPadding: EdgeInsets.all(8),
                  hintText: "Write message...",
                  hintStyle: TextStyle(color: Colors.black54),
                  focusedBorder: OutlineInputBorder(
                      borderSide:
                          BorderSide(width: 1, color: Colors.lightBlue)),
                  enabledBorder: OutlineInputBorder(
                      borderSide: BorderSide(width: 1, color: Colors.grey))),
              onChanged: (value) {
                _inputText = value;
              },
            ),
          ),
          const SizedBox(
            width: 15,
          ),
          FloatingActionButton(
            onPressed: () async {
              //send message
              String to = _conversationType == ChatConversationKind.peer2group
                  ? _toGroup!.chatId
                  : _toUser!.userId;
              if (_inputText != null && _inputText!.isNotEmpty) {
                List<ChatMessage> newMessages = List.castFrom(messages);
                UserInfo? userInfo = await AppHelper.shared.getUserInfo();
                ChatMessage message = ChatMessage(
                    messageSenderReceiverType:
                        ChatMessageSenderReceiverType.sender,
                    toUser: to,
                    fromNickName: userInfo?.nickname,
                    avatarUrl: userInfo?.avatar,
                    message: _inputText!,
                    from: userInfo?.userid ?? "",
                    createTime:
                        DateTime.now().microsecondsSinceEpoch.toString());
                message.messageId = const Uuid().v4();
                newMessages.add(message);
                setState(() {
                  messages = newMessages;
                });
                if (_conversationType == ChatConversationKind.peer2peer) {
                  ChatHelper.sendMessage(to, message, (String msgId) {
                    message.messageId = msgId;
                  });
                } else if (_conversationType ==
                    ChatConversationKind.peer2group) {
                  ChatHelper.sendMessageToGroup(to, message, (String msgId) {
                    message.messageId = msgId;
                  });
                }
                _inputText = null;
                _textEditingController.clear();
                //SchedulerBinding.instance.addPostFrameCallback在listview插入新行的下一幀再執行滾動到最後，否則_scrollController.position.maxScrollExtent算出來的高度不對,
                //也可以用timer替換,SchedulerBinding.instance.addPostFrameCallback會更好
                _scrollToBottom(500);
              }
            },
            backgroundColor: Colors.blue,
            elevation: 0,
            child: const Icon(
              Icons.send,
              color: Colors.white,
              size: 18,
            ),
          )
        ]),
      ),
      Container(
        height: _shouldShowToolsPanel ? 240 : 0,
        width: MediaQuery.of(context).size.width,
        padding: const EdgeInsets.all(13),
        child: CustomScrollView(
          scrollDirection: Axis.horizontal,
          slivers: [
            SliverList(
                delegate: SliverChildBuilderDelegate((context, index) {
              return Container(
                  width: 50,
                  height: 50,
                  margin: const EdgeInsets.all(8),
                  color: Colors.red,
                  child: Text(
                    'test itemfdsf',
                    style: TextStyle(color: Colors.black),
                  ));
            }, childCount: 5))
          ],
        ),
      ),
    ]);
  }
}
